#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include "Segmentation.h"
#include "RegionGrowing.h"
#include <QPainter>
#include <QPixmap>
#include <QFileDialog>
#include <QMouseEvent>
#include <QColorDialog>
#include "Convolution.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->actionExportar->setVisible(false);
    ui->pushButton_2->setDisabled(true);
    ui->pushButton->setEnabled(false);
    ui->btnApplyConv->setEnabled(false);
    ui->btnColor->setEnabled(false);

    //default dimension
    this->defDim = 3;
    this->resizeTable(defDim);

    //define the convolution matrix
    this->cnv = new Convolution(defDim);

    //can't capture the click until there is an image to work with
    this->captureClick = false;

    //default color of the segmented image (green)
    this->segmColor.setRgb(0,255,0);
    QPixmap * p = new QPixmap(this->ui->lblColor->width(),this->ui->lblColor->height());
    p->fill(this->segmColor);
    this->ui->lblColor->setPixmap(*p);

    //default convolutions
    this->ui->comboBox->addItem(" ");
    this->ui->comboBox->addItem("Gaussian smoothing");
    this->ui->comboBox->addItem("Horizontal Sobel");
    this->ui->comboBox->addItem("Vertical Sobel");
    this->ui->comboBox->addItem("Laplacian filter 1");
    this->ui->comboBox->addItem("Laplacian filter 2");

    //stack used for undo changes
    undo = new QStack<QImage>;

    this->ui->btnReset->setVisible(false);
    this->ui->btnUndo->setVisible(false);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

/**
  *
  * Set the original image to show
  *
  */
void MainWindow::setOriginalImage(QImage * img)
{
    ui->lblOriginal->setPixmap(QPixmap::fromImage(*img));
}

/**
  *
  * Set the segmented image to show
  *
  */
void MainWindow::setSegmentedImage(QImage * img)
{
    ui->lblSegmented->setPixmap(QPixmap::fromImage(*img));
}

/**
  *
  * Change the size of the convolution matrix
  *
  */
void MainWindow::resizeTable(int dim)
{
    ui->tblConvolution->setColumnCount(dim);
    ui->tblConvolution->setRowCount(dim);

    for(int i = 0; i < dim; i++)
        for(int j = 0; j < dim; j++)
            ui->tblConvolution->setItem(i,j,new QTableWidgetItem("0"));

}

void MainWindow::on_spnOrderConv_valueChanged(int dim)
{
    this->resizeTable(dim);
}

void MainWindow::on_btnApplyConv_clicked()
{
    delete cnv;

    this->ui->btnReset->setVisible(true);
    this->ui->btnUndo->setVisible(true);

    //capture the convolution dimension
    int nDim = ui->tblConvolution->rowCount();

    //capture the convolution factor
    float factor = ui->txtFactor->text().toFloat();
    qDebug() << factor;


    //create a new convolution matrix from the formulary matrix
    cnv = new Convolution(nDim);
    cnv->setFactor(factor);

    for(int i = 0; i < nDim; i++)
        for(int j = 0; j < nDim; j++)
            cnv->set(i,j,ui->tblConvolution->item(i,j)->text().toInt());


    //apply the convolution to the original image
    QImage * nimg = new QImage(cnv->apply( this->segmImg ));

    //push the previous image on the stack to undo
    this->undo->push(*this->segmImg);
    this->ui->btnUndo->setEnabled(true);

    this->segmImg = nimg;
    this->setSegmentedImage(nimg);

}

void MainWindow::on_actionAbrir_triggered()
{
    QFileDialog * fd = new QFileDialog();
    QString path = fd->getOpenFileName();

    // check whether the path is valid
    if(path != "")
    {
        this->img = new QImage(path);
        this->auxImg = new QImage(path);

        this->setOriginalImage(auxImg);
        this->segmImg = new QImage(*auxImg);

        //enable the buttons that performs actions on the image
        ui->actionExportar->setVisible(true);
        ui->btnApplyConv->setEnabled(true);
        ui->btnColor->setEnabled(true);
        ui->pushButton->setEnabled(true);

        this->captureClick = true;

        //clean the previous segmented image if there is one
        this->ui->lblSegmented->clear();

        this->ui->btnReset->setVisible(false);
        this->ui->btnUndo->setVisible(false);
    }

    delete fd;

}

void MainWindow::on_actionSalir_triggered()
{
    this->close();
}

void MainWindow::mousePressEvent(QMouseEvent * event)
{
    if(this->captureClick)
    {
      //capture the coordinates of the label containing the image
      int xtop = ui->lblOriginal->x() + ui->lblOriginal->width()/2 - this->auxImg->width()/2;
      int ytop = ui->lblOriginal->y() + ui->lblOriginal->height()/2 - this->auxImg->height()/2 + ui->menuBar->height();

      //check whether the click was within the image borders
      if( event->x() >= xtop && event->x() <= (xtop + this->auxImg->width()) )
          if( event->y() >= ytop && event->y() <= (ytop + this->auxImg->height()) )
          {
              //add the seed
              seeds.append(QPoint(event->x() - xtop,event->y() - ytop));

              QString cx,cy;
              cx.setNum(event->x() - xtop);cy.setNum(event->y() - ytop);


              //actualize the seed list in the formulary
              ui->lstSeeds->addItem(QString(QString("( ") + cx + QString(",") + cy + QString(" )")));
              ui->pushButton_2->setEnabled(true);

             //red color
             QColor color(255,0,0);

             //paint the pixel image corresponding to the selected seed
             this->auxImg->setPixel(QPoint(event->x() - xtop,event->y() - ytop),color.rgb());
             this->setOriginalImage(auxImg);
    }
  }

}

void MainWindow::on_pushButton_2_clicked()
{
    //get the position of the seeds list to erase
    int delInd = ui->lstSeeds->currentRow();

    if (delInd > -1)
    {

        //create the coordinate to erase
        QPoint coord(seeds.at(delInd).x(),seeds.at(delInd).y());

        //get the original color of that pixel in the original image
        QColor color = this->img->pixel(coord);

        //set that color
        this->auxImg->setPixel(coord,color.rgb());
        this->setOriginalImage(auxImg);

        //remove the element from the list and restore the list without that element
        seeds.removeAt(delInd);
        ui->lstSeeds->clear();

        for(int i = 0; i < seeds.size(); i++)
        {
            QString cx,cy;
            cx.setNum(seeds.at(i).x()); cy.setNum(seeds.at(i).y());
            ui->lstSeeds->addItem(QString(QString("( ") + cx + QString(",") + cy + QString(" )")));
        }
    }

    if( this->seeds.empty() ) this->ui->pushButton_2->setEnabled(false);


}

void MainWindow::on_pushButton_clicked() //segment button
{

    this->ui->btnReset->setVisible(true);
    this->ui->btnUndo->setVisible(true);

    //create the object Region Growing
    this->rAlg = new RegionGrowing();

    //set the proportion selected by the user
    rAlg->setProportion(this->ui->txtProportion->text().toFloat());

    //check whether the auto tolerance is required and set it on consequence
    if( this->ui->chkAutoTol->isChecked() )
        rAlg->setAutoTolerance(true);
    else
        rAlg->setTolerance(this->ui->txtTolerance->text().toFloat());

    //give the algorithm the image to work with
    rAlg->setImage(this->img);

    // add the seeds selected by the user
    for(int i = 0; i < this->seeds.size(); i++)
    {
        rAlg->addSeedPoint(seeds.at(i).x(),seeds.at(i).y());
    }

    //segment the image
    this->segm = rAlg->segment();
    this->setSegmentedImage(segm->getRegionImage(true,this->segmColor));
    this->segmImg = segm->getRegionImage(true,this->segmColor);

    //push the previous image on the undo stack
    this->undo->push(*this->segmImg);
    this->ui->btnUndo->setEnabled(true);
}


void MainWindow::on_btnColor_clicked()
{
    QColorDialog * dialog = new QColorDialog();
    QColor color = dialog->getColor();
    this->segmColor.setRgb(color.red(),color.green(),color.blue());



    QPixmap * p = new QPixmap(this->ui->lblColor->width(),this->ui->lblColor->height());
    p->fill(this->segmColor);

    this->ui->lblColor->setPixmap(*p);

    //this->ui->pushButton->click();

}

void MainWindow::on_comboBox_currentIndexChanged(int s)
{
    switch(s)
    {
        case 1: //Gaussian smoothing
        {
            this->ui->spnOrderConv->setValue(5);
            this->ui->txtFactor->setText("0.0036630036");
            this->ui->tblConvolution->setItem(0,0,new QTableWidgetItem("1"));
            this->ui->tblConvolution->setItem(0,1,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(0,2,new QTableWidgetItem("7"));
            this->ui->tblConvolution->setItem(0,3,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(0,4,new QTableWidgetItem("1"));
            this->ui->tblConvolution->setItem(1,0,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(1,1,new QTableWidgetItem("16"));
            this->ui->tblConvolution->setItem(1,2,new QTableWidgetItem("26"));
            this->ui->tblConvolution->setItem(1,3,new QTableWidgetItem("16"));
            this->ui->tblConvolution->setItem(1,4,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(2,0,new QTableWidgetItem("7"));
            this->ui->tblConvolution->setItem(2,1,new QTableWidgetItem("26"));
            this->ui->tblConvolution->setItem(2,2,new QTableWidgetItem("41"));
            this->ui->tblConvolution->setItem(2,3,new QTableWidgetItem("26"));
            this->ui->tblConvolution->setItem(2,4,new QTableWidgetItem("7"));
            this->ui->tblConvolution->setItem(3,0,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(3,1,new QTableWidgetItem("16"));
            this->ui->tblConvolution->setItem(3,2,new QTableWidgetItem("26"));
            this->ui->tblConvolution->setItem(3,3,new QTableWidgetItem("16"));
            this->ui->tblConvolution->setItem(3,4,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(4,0,new QTableWidgetItem("1"));
            this->ui->tblConvolution->setItem(4,1,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(4,2,new QTableWidgetItem("7"));
            this->ui->tblConvolution->setItem(4,3,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(4,4,new QTableWidgetItem("1"));
            break;
        };
        case 2: // horizontal Sobel
        {
            this->ui->spnOrderConv->setValue(3);
            this->ui->txtFactor->setText("0.25");
            this->ui->tblConvolution->setItem(0,0,new QTableWidgetItem("1"));
            this->ui->tblConvolution->setItem(0,1,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(0,2,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(1,0,new QTableWidgetItem("2"));
            this->ui->tblConvolution->setItem(1,1,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(1,2,new QTableWidgetItem("-2"));
            this->ui->tblConvolution->setItem(0,0,new QTableWidgetItem("1"));
            this->ui->tblConvolution->setItem(0,1,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(0,2,new QTableWidgetItem("-1"));
            break;
        };
        case 3: // vertical Sobel
        {
            this->ui->spnOrderConv->setValue(3);
            this->ui->txtFactor->setText("0.25");
            this->ui->tblConvolution->setItem(0,0,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(0,1,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(0,2,new QTableWidgetItem("1"));
            this->ui->tblConvolution->setItem(1,0,new QTableWidgetItem("-2"));
            this->ui->tblConvolution->setItem(1,1,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(1,2,new QTableWidgetItem("2"));
            this->ui->tblConvolution->setItem(2,0,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(2,1,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(2,2,new QTableWidgetItem("1"));
            break;
        };
        case 4: //Laplacian filter 1
        {
            this->ui->spnOrderConv->setValue(3);
            this->ui->txtFactor->setText("0.25");
            this->ui->tblConvolution->setItem(0,0,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(0,1,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(0,2,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(1,0,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(1,1,new QTableWidgetItem("4"));
            this->ui->tblConvolution->setItem(1,2,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(2,0,new QTableWidgetItem("0"));
            this->ui->tblConvolution->setItem(2,1,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(2,2,new QTableWidgetItem("0"));
            break;
        };
        case 5: //Laplacian filter 2
        {
            this->ui->spnOrderConv->setValue(3);
            this->ui->txtFactor->setText("0.25");
            this->ui->tblConvolution->setItem(0,0,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(0,1,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(0,2,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(1,0,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(1,1,new QTableWidgetItem("8"));
            this->ui->tblConvolution->setItem(1,2,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(2,0,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(2,1,new QTableWidgetItem("-1"));
            this->ui->tblConvolution->setItem(2,2,new QTableWidgetItem("-1"));
            break;
        }

        default :
        {
            this->ui->spnOrderConv->setValue(3);
            this->ui->txtFactor->setText("1");
            break;

        }

    }
}

void MainWindow::on_btnReset_clicked()
{
      this->setSegmentedImage(this->img);
     // this->auxImg = img;
      this->segmImg = img;
      this->undo->clear();
}

void MainWindow::on_btnUndo_clicked()
{
    QImage undoImg = this->undo->pop();
    QImage * replace = new QImage(undoImg);
    this->segmImg = replace;
    this->setSegmentedImage(replace);

    if( this->undo->isEmpty() )
        this->ui->btnUndo->setEnabled(false);

}

void MainWindow::on_actionExportar_triggered()
{
//    QFileDialog * dialog = new QFileDialog();
//    QFile file;
//    file.
//    dialog->getSaveFileName();
}
